package com.github.byakkili.bim.core.util;

import cn.hutool.core.util.ReflectUtil;
import com.github.byakkili.bim.core.command.CommandHandler;
import io.netty.util.internal.TypeParameterMatcher;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.core.ResolvableType;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Guannian Li
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CommandHandlerUtils {

    private static final Map<Class<? extends CommandHandler>, Class<?>> CACHE = new ConcurrentHashMap<>();

    private static final Method FIND0_METHOD = ReflectUtil.getMethod(TypeParameterMatcher.class, "find0", Object.class, Class.class, String.class);

    public static <T> Class<T> getMsgClass(final CommandHandler commandHandler) {
        return getMsgClass(commandHandler.getClass());
    }

    public static <T> Class<T> getMsgClass(final Class<? extends CommandHandler> commandHandlerClass) {
        Class<?> iMsgClass = CACHE.get(commandHandlerClass);
        if (iMsgClass == null) {
            iMsgClass = ResolvableType.forClass(CommandHandler.class, commandHandlerClass).resolveGeneric(0);
            if (iMsgClass != null) {
                Class<?> prevClass = CACHE.putIfAbsent(commandHandlerClass, iMsgClass);
                if (prevClass != null) {
                    iMsgClass = prevClass;
                }
            }
        }
        @SuppressWarnings("unchecked")
        Class<T> msgClass = (Class<T>) iMsgClass;
        return msgClass;
    }

    @Deprecated
    public static <T> Class<T> getMsgClassOld(final CommandHandler object) {
        return ReflectUtil.invokeStatic(FIND0_METHOD, object, CommandHandler.class, "I");
    }
}
